package com.weatherstation.security;

import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.UnsupportedJwtException;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;

@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {

    @Value("${jwt.header}")
    private String tokenHeader;

    @Value("${jwt.token-prefix}")
    private String tokenPrefix;

    private final JwtTokenUtil jwtTokenUtil;
    private final UserDetailsServiceImpl userDetailsService;
    private final RedisTokenManager redisTokenManager;

    @Autowired
    public JwtAuthenticationFilter(JwtTokenUtil jwtTokenUtil, 
                                  UserDetailsServiceImpl userDetailsService,
                                  RedisTokenManager redisTokenManager) {
        this.jwtTokenUtil = jwtTokenUtil;
        this.userDetailsService = userDetailsService;
        this.redisTokenManager = redisTokenManager;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, 
                                   HttpServletResponse response, 
                                   FilterChain chain) throws ServletException, IOException {
        
        final String requestTokenHeader = request.getHeader(tokenHeader);
        final String requestURI = request.getRequestURI();
        
        logger.debug("处理请求: " + requestURI + ", 方法: " + request.getMethod());

        String username = null;
        String jwtToken = null;

        // 从Authorization头中获取JWT令牌
        if (requestTokenHeader != null && requestTokenHeader.startsWith(tokenPrefix)) {
            jwtToken = requestTokenHeader.substring(tokenPrefix.length()).trim();
            logger.debug("从请求头中提取到JWT令牌: " + jwtToken.substring(0, Math.min(10, jwtToken.length())) + "...");
            try {
                username = jwtTokenUtil.getUsernameFromToken(jwtToken);
                logger.debug("从JWT令牌中提取到用户名: " + username);
            } catch (IllegalArgumentException e) {
                logger.error("无法获取JWT令牌", e);
            } catch (ExpiredJwtException e) {
                logger.error("JWT令牌已过期: " + e.getMessage());
            } catch (MalformedJwtException e) {
                logger.error("无效的JWT令牌: " + e.getMessage());
            } catch (UnsupportedJwtException e) {
                logger.error("不支持的JWT令牌: " + e.getMessage());
            } catch (Exception e) {
                logger.error("JWT令牌处理异常: " + e.getMessage(), e);
            }
        } else {
            logger.debug("Bearer令牌未找到或格式不正确: " + requestTokenHeader);
        }

        // 验证令牌
        if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
            
            // 从Redis中获取存储的令牌
            String storedToken = redisTokenManager.getToken(username);
            
            // 如果Redis中没有令牌或者令牌不匹配，则不进行认证
            if (storedToken == null) {
                logger.warn("Redis中没有找到用户令牌: " + username);
                chain.doFilter(request, response);
                return;
            }
            
            if (!storedToken.equals(jwtToken)) {
                logger.warn("Redis中的令牌与请求中的令牌不匹配");
                logger.debug("Redis令牌: " + storedToken.substring(0, Math.min(10, storedToken.length())) + "...");
                logger.debug("请求令牌: " + jwtToken.substring(0, Math.min(10, jwtToken.length())) + "...");
                chain.doFilter(request, response);
                return;
            }
            
            logger.debug("令牌验证通过，正在加载用户详情");
            UserDetails userDetails = userDetailsService.loadUserByUsername(username);

            // 验证令牌是否有效
            if (jwtTokenUtil.validateToken(jwtToken, userDetails)) {
                logger.debug("JWT令牌有效，设置认证");
                UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
                        userDetails, null, userDetails.getAuthorities());
                authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                
                // 设置安全上下文
                SecurityContextHolder.getContext().setAuthentication(authentication);
                logger.debug("已成功设置安全上下文，用户: " + username + ", 权限: " + userDetails.getAuthorities());
                
                // 检查令牌是否需要续期
                String newToken = redisTokenManager.checkAndRenewToken(username, jwtToken, userDetails);
                
                // 如果令牌已续期，则在响应头中返回新令牌
                if (!newToken.equals(jwtToken)) {
                    logger.debug("JWT令牌已续期");
                    response.setHeader(tokenHeader, tokenPrefix + " " + newToken);
                }
            } else {
                logger.warn("JWT令牌无效，用户: " + username);
            }
        } else if (username == null && requestTokenHeader != null) {
            logger.warn("无法从令牌中提取用户名，请求URI: " + requestURI);
        }
        
        chain.doFilter(request, response);
    }
} 